/**
 * Copyright (c) 2011 Technical Centre Radio Systems Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ua.tcrs.tabula.container;

import java.util.Map;
import java.util.Hashtable;
import java.util.Arrays;

import ua.tcrs.tabula.util.Iterables;
import ua.tcrs.tabula.util.Predicate;
import ua.tcrs.tabula.util.Reflect;

public class BaseServiceRegistry implements ServiceRegistry {
	protected Map<Class<?>,Object> services = new Hashtable<Class<?>,Object>();
	ServiceFactory parent = null;
	public BaseServiceRegistry() {
	}
	public BaseServiceRegistry( ServiceFactory parent ) {
		this.parent = parent;
	}
	@SuppressWarnings("unchecked")
	public <T> T getService( Class<T> srvIface ) {
		if ( services.containsKey( srvIface ) ) {
			return (T)services.get( srvIface );
		} else {
			return parent == null ? null : parent.getService( srvIface );
		}
	}
	public boolean containsService( Class<?> srvIface ) {
		return services.containsKey( srvIface ) || ( parent == null ? false : parent.containsService( srvIface ) );
	}
	public void bindService( Object srvInstance ) {
		Iterable<Class<?>> ifaces = Iterables.filter( Reflect.allInterfaces( srvInstance.getClass() ), new Predicate<Class<?>>() {
			public boolean apply( Class<?> iface ) { return !iface.getName().startsWith("java"); }
		} );
		srvInstance = wrapService( srvInstance, ifaces );
		for ( Class<?> srvIface: ifaces ) {
			addService( srvIface, srvInstance );
		}
	}
	public void bindService( Object srvInstance, Class<?>... srvIfaces ) {
		srvInstance = wrapService( srvInstance, Arrays.asList( srvIfaces ) );
		for ( Class<?> srvIface: srvIfaces ) addService( srvIface, srvInstance );
	}
	protected Object wrapService( Object srvInstance, Iterable<Class<?>> srvIfaces ) {
		return srvInstance;
	}
	protected void addService( Class<?> srvIface, Object srvInstance ) {
		if ( containsService( srvIface ) ) {
			throw new RuntimeException( "Service "+srvIface+" already present in registry" );
		} else {
			services.put( srvIface, srvInstance );
		}
	}
}

